#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Diagnostics;
using System.Security.Permissions;
using System.Xml.Serialization;
using Adoor.Expression;
using Adoor.Expression.AST;

namespace Adoor.Relational
{
	/// <remarks>
	/// A relational operator is an object describing a tabular data set. A relational operator is the
	/// combination of one more basic relational operators of types <see cref="AliasOperator"/>, <see cref="FilterOperator/>,
	/// <see cref="JoinOperator/>, <see cref="SortOperator"/>.
	/// A relational operator has list of correlations (property <see cref="RelationalOperator.Correlations"/>) and a collection of columns
	/// (property <see cref="RelationalOperator.Columns"/> which is a ICollection containing objects of type <see cref="ExpressionName"/>).
	/// A relational operator can be further combined by calling one of the methods <see cref="RelationalOperator.Filter"/>,
	/// <see cref="RelationalOperator.Project"/> and <see cref="RelationalOperator.Sort"/>
	/// which return the corresponding operator.
	/// 
	/// A relational operator can be evaluated through a <see cref="IRelationalOperatorEvaluator"/>.
	/// </remarks>
	public abstract class RelationalOperator : RelationalElement
	{
	

		[XmlIgnore]
		public abstract ICollection<Adoor.Expression.AST.ExpressionName> Columns { get; }

		// TODO: public abstract ICollection/*IRelationalOperator*/ Correlations;
		/// <summary>
		/// The list of allowed qualifiers for Columns.
		/// </summary>
		[XmlIgnore]
		public abstract IList<string> Correlations { get; }

		/// <summary>
		/// Evaluate the current expression through an evaluator. The current expression is decomposed
		/// into basic relational operators which are then evaluated by the evaluator by calling the 
		/// corresponding methods.
		/// </summary>
		/// <param name="e">The relational evaluator to evaluate the current expression through.</param>
		public abstract void EvaluateFrom(IRelationalOperatorEvaluator e);

		/// <summary>
		/// Returns a new relational expression which is a filter on the current expression.
		/// </summary>
		/// <param name="condition">A condition that is applied on each row returned by the current relational
		/// expression.
		/// The condition may contain "?" placeholders whose values are passed in the "args" argument.
		/// <param name="condition"></param>
		public virtual RelationalOperator Filter(string condition)
		{
			ExpressionParser ep = new ExpressionParser();
			return new FilterOperator(this, ep.ParseCondition(condition));
		}

		public virtual RelationalOperator Filter(ExpressionNode condition)
		{
			return new FilterOperator(this, condition);
		}

		/// <summary>
		/// Returns a new relational expression which is a projection on the current operator. The new relational
		/// expression is similar to the current expression except for the list of columns.
		/// </summary>
		/// <param name="columns">A ICollection of SelectColumn objects used for the projection.</param>
		public virtual RelationalQuery Project(ICollection<Expression.AST.SelectExpression>/*SelectColumn*/ columns)
		{
			return new ProjectQuery(this, columns);
		}

		public virtual RelationalQuery Project(params SelectExpression[] columns)
		{
			return new ProjectQuery(this, columns);
		}
		/// <summary>
		/// Returns a new relational expression which is a sorted version of the current expression. The new
		/// relational expression is similar to the current expression except for the sort order.
		/// </summary>
		/// <param name="sortList">An array containing the columns of type <see cref="SortExpression"/>.</param>
		public virtual RelationalOperator Sort(SortExpression[] sortList)
		{
			return new SortOperator(this, sortList);
		}

		/// <summary>
		/// Returns a new relational expression which is the join of the current expression with another expression (source2)
		/// on columns "column1" and "column2" starting from "correlation". The alias of the new expression is a unique temporary
		/// string and IsAnonymous = true;
		/// </summary>
		public RelationalOperator Join(bool isOuter, string column1, RelationalQuery source2, string column2, string correlation)
		{
			return new JoinOperator(isOuter, this, column1, source2, column2, correlation);
		}
		
		/// <summary>
		/// Returns a new relational expression which is the join of the current expression with another expression (source2)
		/// on columns "column1" and "column2" starting from "correlation". IsAnonymous = false.
		/// </summary>
		public RelationalOperator Join(bool isOuter, string column1, RelationalQuery source2, string column2, string correlation, string alias)
		{
			return new JoinOperator(isOuter, this, column1, source2, column2, correlation, alias);
		}

		public RelationalOperator Cross(RelationalOperator source2, string alias, ExpressionNode joinCondition, bool isOuterJoin)
		{
			return new CrossOperator(this, source2, alias, joinCondition, isOuterJoin);
		}

		public RelationalOperator CrossQuery(RelationalQuery source2Query, string alias, ExpressionNode joinCondition, bool isOuterJoin)
		{
			return new CrossQueryOperator(this, source2Query, alias, joinCondition, isOuterJoin);
		}

		// select * from this where exists (select 1 from source where correlation1.column1 = correlation2.column2)
		public RelationalOperator Intersect(string correlation1, string column1, RelationalOperator source2, string correlation2, string column2)
		{
			return new IntersectOperator(this, correlation1, column1, source2, correlation2, column2);
		}

		// select * from this where not exists (select 1 from source where correlation1.column1 = correlation2.column2)
		public RelationalOperator Minus(string correlation1, string column1, RelationalOperator source2, string correlation2, string column2)
		{
			return new IntersectOperator(this, correlation1, column1, source2, correlation2, column2, true);
		}

		public RelationalOperator GroupBy(RelationalOperator source, SelectExpression[] select, GroupByExpression[] groupBy, HavingExpression having)
		{
			return new GroupByOperator(source, select, groupBy, having);
		}

		public RelationalQuery AsQuery()
		{
			return new UnqualifierQuery(this);			
		}

		private object tag;
		public object Tag
		{
			get{ return tag;}
			set{ tag = value; }
		}

		private object parent;
		public object Parent
		{
			get{ return parent; }
			set{ parent = value; }
		}
	}

	/// <summary>
	/// A relational operator evaluator is an object that knows how to evaluate relational operators. To evaluate
	/// a relational operator, call IRelationalOperator.EvaluateFrom(IRelationalOperatorEvaluator). EvaluateFrom
	/// decomposes the relational operator into basic relational operators which specialized descendants of the
	/// evaluator know how to evaluate (for the aficionados of design patterns the 
	/// <see cref="RelationalOperator"/>/<see cref="IRelationalOperatorEvaluator"/> couple follows the GOF's "visitor pattern").
	/// The result of the evaluation as well as potential extra parameters are generally exposed by the
	/// specialized evaluator.
	/// </summary>
	public interface IRelationalOperatorEvaluator
	{
		/// <summary>
		/// Evaluates the basic relational operator Alias.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="a">The basic relational operator Alias to evaluate.</param>
		void EvaluateAlias(AliasOperator a);

		/// <summary>
		/// Evaluates the basic relational operator Join.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="j">The basic relational operator Join to evaluate.</param>
		void EvaluateJoin(JoinOperator j);

		/// <summary>
		/// Evaluates the basic relational operator Cross.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="c">The basic relational operator Cross to evaluate.</param>
		void EvaluateCross(CrossOperator c);

		/// <summary>
		/// Evaluates the basic relational operator Cross.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="c">The basic relational operator Cross to evaluate.</param>
		void EvaluateCrossQuery(CrossQueryOperator c);

		/// <summary>
		/// Evaluates the basic relational operator Filter
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="f">The basic relational operator Filter to evaluate.</param>
		void EvaluateFilter(FilterOperator f);

		/// <summary>
		/// Evaluates the basic relational operator Sort.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="s">The basic relational operator Sort to evaluate.</param>
		void EvaluateSort(SortOperator s);

		/// <summary>
		/// Evaluates the basic relational operator Intersect.
		/// The precise meaning of "evaluate" is defined by the class supporting the interface.
		/// </summary>
		/// <param name="i">The basic relational operator Intersect to evaluate.</param>
		void EvaluateIntersect(IntersectOperator i);

		void EvaluateGroupBy(GroupByOperator g);

		void EvaluateScanQueryOperator(ScanQueryOperator s);
	}

	/// <summary>
	/// Basic relational operator. Transforms the relational query <see cref="AliasOperator.Source"/> into a relational operator par prefixing
	/// each column name with <see cref="AliasOperator.Alias"/>. <see cref="AliasOperator.Alias"/> also becomes the only correlation of the operator.
	/// </summary>
	public class AliasOperator: RelationalOperator
	{
		public AliasOperator()
		{
		}

		public AliasOperator(RelationalQuery source, string alias)
		{
			this.source = source;
			if(this.Source != null)
				this.Source.Parent = this;
			this.alias = alias;
			this.correlations = new List<string>();
			this.correlations.Add(this.Alias);
			this.columns = new ExpressionName[this.Source.DataColumns.Count];
			int i = 0;
			foreach(object o in this.Source.DataColumns)
			{
				if(o is DataColumn)
				{
					this.columns[i++] = new ExpressionName(alias, ((DataColumn) o).ColumnName);
				}
				else
				{
					this.columns[i++] = new ExpressionName(alias, ((DataColumn) o).ColumnName);
				}
			}
		}

		public string Alias
		{
			get { return this.alias; }
			set { this.alias = value; }
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get { return this.columns; }
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get { return this.correlations; } 
		}

		[XmlIgnore]
		public RelationalQuery Source
		{
			get { return this.source; } 
			set { this.source = value; 
				if(this.Source != null)
					this.Source.Parent = this; }
		}

		[XmlElement(typeof(ScanQuery))]
		[XmlElement(typeof(UnionQuery))]
		public object SourceInfo
		{
			get { return this.source; }
			set { this.source = (RelationalQuery)value; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateAlias(this);
		}

		private RelationalQuery source;
		private List<string> correlations;
		private string alias;
		private ExpressionName[] columns;
	}

	

	/// <summary>
	/// Basic relational operator.
	/// </summary>
	public class JoinOperator: RelationalOperator
	{
		public JoinOperator()
		{
		}

		public JoinOperator(bool isOuter, RelationalOperator source1, string column1, RelationalQuery source2, string column2, string correlation):
			this(isOuter, source1, column1, source2, column2, correlation, "")
		{}
		
		public JoinOperator(bool isOuterJoin, RelationalOperator source1, string column1, RelationalQuery source2, string column2, string correlation, string alias)
		{
			this.alias = alias;
			this.isOuterJoin = isOuterJoin;
			this.source1 = source1;
			if(this.source1 != null)
				this.source1.Parent = this;

			this.column1 = column1;
			
            this.source2 = source2;
			if(this.source2 != null)
				this.source2.Parent = this;
			this.column2 = column2;
			
            this.correlation = correlation;

		}

		public string Alias
		{
			get { return this.alias; }
			set { this.alias = value; }
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get
			{
                List<ExpressionName> result = new List<ExpressionName>();
				foreach(ExpressionName c in source1.Columns)
					result.Add(c);
				foreach(DataColumn o in source2.DataColumns)
				{
					if(o is DataColumn)
					{
						result.Add(new ExpressionName(Alias, ((DataColumn) o).ColumnName));
					}
                    //else
                    //{
                    //    result.Add(new ExpressionName(Alias, ((DataColumn) o).ColumnName));
                    //}
				}
				return result;
			}
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get
			{
				if (this.correlations == null)
				{
					this.correlations = new List<string>();
					foreach(string s in Source1.Correlations)
						this.correlations.Add(s);
					this.correlations.Add(Alias);
				}
				return this.correlations;
			}
		}

		public bool IsOuterJoin
		{ 
			get { return this.isOuterJoin; } 
			set { this.isOuterJoin = value; }
		}

		[XmlIgnore]
		public RelationalOperator Source1
		{
			get { return this.source1; } 
			set 
			{
				this.source1 = value; 
				if(this.source1 != null)
					this.Source1.Parent = this;
			}
		}

		[XmlArray("Source1")]
		[XmlArrayItem(typeof(AliasOperator))]
		[XmlArrayItem(typeof(FilterOperator))]
		[XmlArrayItem(typeof(JoinOperator))]
		public object[] SourceInfo1
		{
			get { return new object[]{this.source1}; }
			set { this.source1 = (RelationalOperator)value[0]; }
		}

		public string Column1
		{ 
			get { return this.column1; }
			set { this.column1 = value; }
		}

		[XmlIgnore]
		public RelationalQuery Source2
		{
			get { return this.source2; } 
			set 
			{
				this.source2 = value; 
				if(this.Source2 != null)
					this.Source2.Parent = this; 
			}
		}

		[XmlArray("Source2")]
		[XmlArrayItem(typeof(ScanQuery))]
		[XmlArrayItem(typeof(UnionQuery))]
		public object[] SourceInfo2
		{
			get { return new object[]{this.source2}; }
			set { this.source2 = (RelationalQuery)value[0]; }
		}

		public string Column2 
		{ 
			get { return this.column2; }
			set { this.column2 = value; }
		}
		
		public string Correlation
		{
			get { return this.correlation; }
			set { this.correlation = value; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateJoin(this);
		}

		private string alias;
		private bool isOuterJoin;
		private RelationalOperator source1;
		private string column1;
		private RelationalQuery source2;
		private string column2;
		private string correlation;
		private List<string> correlations;
	}

	/// <summary>
	/// Default implementation for ICrossOperator
	/// </summary>
	public class CrossOperator: RelationalOperator
	{
		public CrossOperator()
		{
		}

		public CrossOperator(RelationalOperator source1, RelationalOperator source2, string alias, ExpressionNode joinCondition, bool isOuterJoin)
		{
			this.alias = alias;
			this.source1 = source1;
			if(this.source1 != null)
				this.source1.Parent = this;
			this.source2 = source2;
			if(this.source2 != null)
				this.source2.Parent = this;
			this.joinCondition = joinCondition;
			this.isOuterJoin = isOuterJoin;
		}

		public CrossOperator(RelationalOperator source1, RelationalQuery source2query, string alias, ExpressionNode joinCondition, bool isOuterJoin)
		{
			this.alias = alias;
			this.source1 = source1;
			if(this.source1 != null)
				this.source1.Parent = this;
			this.source2query = source2query;
			if(this.source2query != null)
				this.source2query.Parent = this;
			this.joinCondition = joinCondition;
			this.isOuterJoin = isOuterJoin;
		}

		public string Alias
		{
			get { return this.alias; }
			set { this.alias = value; }
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get
			{
                List<ExpressionName> result = new List<ExpressionName>();
				foreach(ExpressionName c in source1.Columns)
				{
					result.Add(c);
				}
				foreach(ExpressionName c in source2.Columns)
				{
					result.Add(new ExpressionName(this.Alias, c.Value));
				}
				return result;
			}
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get
			{
				if (this.correlations == null)
				{
					this.correlations = new List<string>();
					foreach(string s in Source1.Correlations)
						this.correlations.Add(s);
					this.correlations.Add(Alias);
				}
				return this.correlations;
			}
		}

		[XmlIgnore]
		public RelationalOperator Source1
		{
			get { return this.source1; } 
			set 
			{
				this.source1 = value; 
				if(this.source1 != null)
					this.Source1.Parent = this; 
			}
		}

		[XmlArray("Source1")]
		[XmlArrayItem(typeof(AliasOperator))]
		[XmlArrayItem(typeof(FilterOperator))]
		[XmlArrayItem(typeof(JoinOperator))]
		public object[] SourceInfo1
		{
			get { return new object[]{this.source1}; }
			set { this.source1 = (RelationalOperator)value[0]; }
		}

		[XmlIgnore]
		public RelationalOperator Source2
		{
			get { return this.source2; } 
			set 
			{
				this.source2 = value; 
				if(this.Source2 != null)
					this.Source2.Parent = this; 
			}
		}

		[XmlIgnore]
		public RelationalQuery Source2Query
		{
			get { return this.source2query; } 
			set 
			{
				this.source2query = value; 
				if(this.Source2Query != null)
					this.Source2Query.Parent = this;
			}
		}

		public ExpressionNode JoinCondition
		{
			get{ return joinCondition; }
		}

		public bool IsOuterJoin
		{
			get{ return isOuterJoin; }
		}

		[XmlArray("Source2")]
		[XmlArrayItem(typeof(AliasOperator))]
		[XmlArrayItem(typeof(FilterOperator))]
		[XmlArrayItem(typeof(JoinOperator))]
		public object[] SourceInfo2
		{
			get { return new object[]{this.source2}; }
			set { this.source2 = (RelationalOperator)value[0]; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateCross(this);
		}

		private string alias;
		private RelationalOperator source1;
		private RelationalOperator source2;
		private RelationalQuery source2query;
		private ExpressionNode joinCondition;
		private bool isOuterJoin;
		private List<string> correlations;
	}

	/// <summary>
	/// Default implementation for ICrossOperator
	/// </summary>
	public class CrossQueryOperator: RelationalOperator
	{
		public CrossQueryOperator()
		{
		}

		public CrossQueryOperator(RelationalOperator source1, RelationalQuery source2query, string alias, ExpressionNode joinCondition, bool isOuterJoin)
		{
			this.alias = alias;
			this.source1 = source1;
			if(this.source1 != null)
				this.Source1.Parent = this;

			this.source2query = source2query;
			if(this.Source2Query != null)
				this.Source2Query.Parent = this;
			this.joinCondition = joinCondition;
			this.isOuterJoin = isOuterJoin;
		}

		public string Alias
		{
			get { return this.alias; }
			set { this.alias = value; }
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get
			{
                List<ExpressionName> result = new List<ExpressionName>();
				foreach(ExpressionName c in source1.Columns)
				{
					result.Add(c);
				}
//				foreach(DataColumn dci in Source2Query.DataColumns)
//				{					
//					Debug.Assert(c.Qualifier == ""); // TODO ????
//					result.Add(new ExpressionName(this.Alias, c.Value));
//				}
				return result;
			}
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get
			{
				if (this.correlations == null)
				{
					this.correlations = new List<string>();
					foreach(string s in Source1.Correlations)
						this.correlations.Add(s);
					this.correlations.Add(Alias);
				}
				return this.correlations;
			}
		}

		[XmlIgnore]
		public RelationalOperator Source1
		{
			get { return this.source1; } 
			set 
			{ 
				this.source1 = value; 
				if(this.Source1 != null)
					this.Source1.Parent = this;
			}
		}

		[XmlArray("Source1")]
		[XmlArrayItem(typeof(AliasOperator))]
		[XmlArrayItem(typeof(FilterOperator))]
		[XmlArrayItem(typeof(JoinOperator))]
		public object[] SourceInfo1
		{
			get { return new object[]{this.source1}; }
			set { this.source1 = (RelationalOperator)value[0]; }
		}

		[XmlIgnore]
		public RelationalQuery Source2Query
		{
			get { return this.source2query; } 
			set 
			{ 
				this.source2query = value; 
				if(this.source2query != null)
					this.source2query.Parent = this;
			}
		}

		public ExpressionNode JoinCondition
		{
			get{ return joinCondition; }
		}

		public bool IsOuterJoin
		{ 
			get { return this.isOuterJoin; } 
			set { this.isOuterJoin = value; }
		}
//
//		[XmlArray("Source2")]
//		[XmlArrayItem(typeof(AliasOperator))]
//		[XmlArrayItem(typeof(FilterOperator))]
//		[XmlArrayItem(typeof(JoinOperator))]
//		public object[] SourceInfo2
//		{
//			get { return new object[]{this.source2}; }
//			set { this.source2 = (RelationalOperator)value[0]; }
//		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateCrossQuery(this);
		}

		private string alias;
		private bool isOuterJoin;
		private RelationalOperator source1;
		private RelationalQuery source2query;
		private ExpressionNode joinCondition;
		private List<string> correlations;
	}

	/// <summary>
	/// Default implementation for ICrossOperator
	/// </summary>
	public class ScanQueryOperator: RelationalOperator
	{
		public ScanQueryOperator()
		{
		}

		public ScanQueryOperator(RelationalQuery scanQuery, string alias)
		{
			Debug.Assert(alias != "");
			this.alias = alias;
			this.scanQuery = scanQuery;
			if(this.scanQuery != null)
				this.scanQuery.Parent = this;

			this.correlations = new List<string>();
			this.correlations.Add(this.Alias);
			
			this.columns = new ExpressionName[this.scanQuery.DataColumns.Count];
			int i = 0;
			foreach(object o in this.scanQuery.DataColumns)
			{
				if(o is DataColumn)
				{
					this.columns[i++] = new ExpressionName(alias, ((DataColumn) o).ColumnName);
				}
				else
				{
					this.columns[i++] = new ExpressionName(alias, ((DataColumn) o).ColumnName);
				}
			}
		}

		public string Alias
		{
			get { return this.alias; }
			set { this.alias = value; }
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get
			{
				return (ICollection<ExpressionName>) this.columns;
			}
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get
			{
				return this.correlations;
			}
		}

	

		[XmlIgnore]
		public RelationalQuery ScanQuery
		{
			get { return this.scanQuery; } 
			set 
			{ 
				this.scanQuery = value; 
				if(this.scanQuery != null)
					this.scanQuery.Parent = this;
			}
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateScanQueryOperator(this);
		}

		private string alias;
		private RelationalQuery scanQuery;
		private ExpressionNode[] columns;
		private List<string> correlations;
	}

	/// <summary>
	/// Basic relational operator. Describes the set of rows contained in the set described by <see cref="FilterOperator.Source"/> and that
	/// verify the condition <see cref="FilterOperator.Condition"/>.
	/// The condition may contain "?" placeholders whose values are passed to query engines as external arguments.
	/// </summary>
	public class FilterOperator: RelationalOperator
	{
		public FilterOperator()
		{
		}

		public FilterOperator(RelationalOperator source, ExpressionNode condition)
		{
			this.source = source;
			if(this.source != null)
				this.source.Parent = this;
			this.condition = condition;
		}

		[XmlIgnore]
		public override ICollection<ExpressionName> Columns
		{
			get { return source.Columns; }
		}

		[XmlIgnore]
		public override IList<string> Correlations
		{
			get { return Source.Correlations; } 
		}

		[XmlIgnore]
		public RelationalOperator Source
		{
			get { return this.source; } 
			set 
			{ 
				this.source = value;
				if(this.source != null)
					this.source.Parent = this;
			}
		}

		[XmlElement(typeof(AliasOperator))]
		[XmlElement(typeof(FilterOperator))]
		[XmlElement(typeof(JoinOperator))]
		public object SourceInfo
		{
			get { return this.source; }
			set { this.source = (RelationalOperator)value; }
		}

		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Condition
		{
			get { return this.condition; }
			set { this.condition = value; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateFilter(this);
		}

		private RelationalOperator source;
		private ExpressionNode condition;
	}

	/// <summary>
	/// Basic relational operator.
	/// </summary>
	public class SortOperator: RelationalOperator
	{
		public SortOperator(RelationalOperator source, SortExpression[] sortOrder)
		{
			this.source = source;
			if(this.source != null)
				this.source.Parent = this;
			this.sortOrder = sortOrder;
		}

		public SortOperator()
		{
		}

		public override ICollection<ExpressionName> Columns
		{
			get { return this.Source.Columns; }
		}

		public override IList<string> Correlations
		{
			get { return Source.Correlations; } 
		}

		public RelationalOperator Source
		{
			get { return this.source; }
		}

		public SortExpression[] SortOrder
		{
			get { return this.sortOrder; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateSort(this);
		}

		private RelationalOperator source;

		private SortExpression[] sortOrder; 
	}

	/// <summary>
	/// Basic relational operator.
	/// </summary>
	public class GroupByOperator: RelationalOperator
	{
		public GroupByOperator(RelationalOperator source, SelectExpression[] selectColumns, GroupByExpression[] groupBy, HavingExpression having)
		{
			this.source = source;
			if(this.source != null)
				this.source.Parent = this;
			this.groupBy = groupBy;
			this.having = having;
			this.selectColumns = selectColumns;
		}

		public GroupByOperator()
		{
		}

		public override ICollection<ExpressionName> Columns
		{
			get { return this.Source.Columns; }
		}

		public override IList<string> Correlations
		{
			get { return Source.Correlations; } 
		}

		public RelationalOperator Source
		{
			get { return this.source; }
		}

		public GroupByExpression[] GroupByColumns
		{
			get { return this.groupBy; }
		}

		public SelectExpression[] SelectColumns
		{
			get { return this.selectColumns; }
		}

		

		public HavingExpression Having
		{
			get { return this.having; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateGroupBy(this);
		}

		private RelationalOperator source;

		private GroupByExpression[] groupBy;
		private SelectExpression[] selectColumns;
		private HavingExpression having;
	}

	public class IntersectOperator: RelationalOperator
	{
		public IntersectOperator(RelationalOperator source1, string correlation1, string column1, RelationalOperator source2, string correlation2, string column2)
			: this(source1, correlation1, column1, source2, correlation2, column2, false)
		{
		}

		public IntersectOperator(RelationalOperator source1, string correlation1, string column1, RelationalOperator source2, string correlation2, string column2, bool isMinus)
		{
			this.source1 = source1;
			if(this.source1 != null)
				this.source1.Parent = this;
			this.correlation1 = correlation1;
			this.column1 = column1;
			this.source2 = source2;
			if(this.source2 != null)
				this.source2.Parent = this;
			this.correlation2 = correlation2;
			this.column2 = column2;
			this.isMinus = isMinus;
		}

		public override ICollection<ExpressionName> Columns
		{
			get { return this.Source1.Columns; }
		}

		public override IList<string> Correlations
		{
			get { return this.Source1.Correlations; } 
		}

		public RelationalOperator Source1
		{
			get { return this.source1; }
		}

		public string Correlation1
		{
			get { return this.correlation1; }
		}

		public string Column1
		{
			get { return this.column1; }
		}

		public RelationalOperator Source2
		{
			get { return this.source2; }
		}

		public string Correlation2
		{
			get { return this.correlation2; }
		}

		public string Column2
		{
			get { return this.column2; }
		}

		public bool IsMinus
		{
			get { return this.isMinus; }
		}

		public override void EvaluateFrom(IRelationalOperatorEvaluator e)
		{
			e.EvaluateIntersect(this);
		}

		private RelationalOperator source2;
		private string correlation1;
		private string column1;
		private RelationalOperator source1;
		private string correlation2;
		private string column2;
		private bool isMinus;

	}
}
